function requiredFieldValidator(value) {
    if (value == null || value == undefined || !value.length) {
        return { valid: false, msg: "This is a required field" };
    } else {
        return { valid: true, msg: null };
    }
}

var mFroms = {
    M: 'manufactory',
    P: 'purchase'
}

var columnFilters = {};

function toggleFilterRow() {
    grid.setTopPanelVisibility(!grid.getOptions().showTopPanel);
}

// top panel
$(".grid-header .ui-icon")
    .addClass("ui-state-default ui-corner-all")
    .mouseover(function (e) {
        $(e.target).addClass("ui-state-hover")
    })
    .mouseout(function (e) {
        $(e.target).removeClass("ui-state-hover")
    });

function PopulateSelect(select, dataSource, addBlank) {
    var index, len, newOption;
    if (addBlank) { select.appendChild(new Option('', '')); }
    $.each(dataSource, function (value, text) {
        newOption = new Option(text, value);
        select.appendChild(newOption);
    });
};

// stackoverflow.com/questions/2532218
function pickRandomFromroperty(obj) {
    var result;
    var count = 0;
    for (var prop in obj)
        if (Math.random() < 1 / ++count)
            result = prop;
    return result;
}

function PopulateSelect(select, dataSource, addBlank) {
    var index, len, newOption;
    if (addBlank) { select.appendChild(new Option('', '')); }
    $.each(dataSource, function (value, text) {
        newOption = new Option(text, value);
        select.appendChild(newOption);
    });
};

var TaskNameFormatter = function (row, cell, value, columnDef, dataContext) {
    value = value.replace(/&/g, "&amFrom;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
    var spacer = "<span style='display:inline-block;height:1px;width:" + (15 * dataContext["indent"]) + "px'></span> ";
    var idx = dataView.getIdxById(dataContext.id);
    var levelNum = doLevelNum(dataContext["indent"]);
    var item = data[idx + 1];
    if (item && item.indent > data[idx].indent) {
        if (dataContext._collapsed) {
            return spacer + " <span class='toggle expand'></span>&nbsp;" + levelNum + partStatus(dataContext);
        } else {
            return spacer + " <span class='toggle collapse'></span>&nbsp;" + levelNum + partStatus(dataContext);
        }
    } else {
        return spacer + " <span class='toggle'></span>&nbsp;" + levelNum + partStatus(dataContext);
    }
};

function doLevelNum(ix) {
    return " [" + (ix + 1) + "] ";
}

function partStatus(data) {
    return "<a " + (data.state ? "style='color:red'" : "") + ">" + data.part + "</a>  <input style='width:20px;border-style:none' class='bom-past' value='[..]'></input>" ;
}

var searchString = "";
var dataView;
var grid;
var levelIx = 0;
var data = [];
var groups = [[{ "group": "D", "name": "design", "expend": true }, { "group": "S", "name": "process", "expend": true }, { "group": "G", "name": "other", "expend": true }]];
var columns = [
    { id: "num", group: ["D"], expend: true },
    { id: "checked", group: ["D"], expend: true },
    { id: "part", name: "part", expend: true, group: ["D"], field: "part", width: 250, cssClass: "cell-title", formatter: TaskNameFormatter, editor: Slick.Editors.Text, validator: requiredFieldValidator },
    { id: "operator", name: "operator", group: ["D"], field: "operator", width: 100, formatter: CustomerFormatter },
    { id: "draw", name: "draw", group: ["S"], field: "draw", width: 200, resizable: false, headerMenus: { filter: true } },
    { id: "createTime", name: "create time", group: ["S"], field: "createTime", width: 200, resizable: false, editor: Slick.Editors.Date },
    { id: "description", name: "remark", group: ["G"], field: "description", minWidth: 200, editor: Slick.Editors.LongText },
    { id: "qty", name: "qty", group: ["G"], field: "qty", minWidth: 80, editor: Slick.Editors.Text },
    { id: "mFrom", name: "M/P", group: ["G"], width: 80, minWidth: 20, maxWidth: 200, cssClass: "cell-effort-driven", field: "mFrom", editor: Slick.Editors.Select2Editor, dataSource: mFroms },
    { id: "oth1", name: "oth1", group: ["G"], field: "oth1", minWidth: 100, editor: Slick.Editors.Text },
    { id: "oth2", name: "oth2", group: ["G"], field: "oth2", minWidth: 400, editor: Slick.Editors.Text },
    { id: "oth3", name: "oth3", group: ["G"], field: "oth3", minWidth: 600, editor: Slick.Editors.Text },
];

var options = {
    editable: true,
    enableAddRow: true,
    enableCellNavigation: true,
    cellHighlightCssClass: "changed",
    cellFlashingCssClass: "current",
    asyncEditorLoading: false,
    frozenColumn: 3,
    headerGroups: groups,
    showHeaderRow: false,
    autoEdit: false,
    rowHeight: 30,
    fileName: function () {
        return "bom.xlsx";
    },
    rowKey: function (row) {
        return row.part;
    },
    equalRow: function (row, otherRow) {
        if (row && otherRow) {
            return row.part == otherRow.parentNo;
        }
    },
    topPanelHeight: 30
};

var percentComFromleteThreshold = 0;
var searchString = "";

// 过滤
function myFilter(item, args) {

    if (!columnFilter(item)) {
        return false;
    }
    if (item.parent != null) {
        var parent = data[item.parent];

        var temFromParents = [];
        while (parent && !(temFromParents.indexOf(parent) > 0)) {
            if (parent._collapsed) {
                return false;
            }

            temFromParents.push(parent);

            // stone 20210312 break recycle 
            if (data[parent.parent] == parent) {
                return true;
            }
            parent = data[parent.parent];
        }
    }

    if (args && args.searchString != "" && item["part"].indexOf(args.searchString) == -1) {
        return false;
    }

    if (levelIx && levelIx > 0) {
        return item["indent"] < levelIx;
    }

    return true;
}

function partSort(a, b) {
    return a["part"] - b["part"];
}

function CustomerFormatter(row, cell, value, columnDef, dataContext) {
    return "<a   class='cell-a-add  cell-a-btn'>+</a>"
        + " <a   class='cell-a-delete cell-a-btn' >-</a > "
        + "<a class='cell-a-menu cell-a-btn'  >操作</a >";
}


function columnFilter(item) {

    for (var columnId in columnFilters) {
        if (columnId !== undefined && columnFilters[columnId] !== "") {
            var filterValue = columnFilters[columnId] + "";
            var value = grid.getDataItemValueForField(item, columnId) + "";
            if (filterValue.startsWith("${") && filterValue.endsWith("}")) {
                filterValue = filterValue.substring(2, filterValue.length - 1) + "";

                if (filterValue == "") {
                    var filterResult = value == filterValue || !value;
                    if (!filterResult) {
                        return false;
                    }
                    continue;
                }
            }

            if (value && value.indexOf(filterValue) == -1 || !value) {
                return false;
            }
        }
    }
    return true;
}

function headerMenuAttatchment(columns) {
    for (var i = 0; i < columns.length; i++) {
        if (columns[i].headerMenus) {
            columns[i].header = {
                menu: {
                    items: []
                }
            };

            if (columns[i].headerMenus.filter) {
                columns[i].header.menu.items.push(
                    {
                        iconCssClass: "icon-help",
                        title: "查询:",
                        command: "filter",
                        content: " <input id='filterQ' style='width:100px; margin:3px;padding-right:15px' value='${}' ></input> <a class='filterQa' style='width:30px;height:30px;position:absolute;margin:6px;right:-10px'><span class='glyphicon glyphicon-remove'></span></a>",
                        preventDefault: true,
                        selfbind: filterBind
                    });
            }
        };
    }
}
function filterBind($target) {
    $target.keyup(function (e) {
        var col = $(this).data("column");
        columnFilters[col.field] = $target.val();
        col.filter = $target.val();
        grid.setFilterColumn(grid.getColumnIndex(col.id), $target.val());
        dataView.refresh();
    });

    if ($target.hasClass("filterQa") || $target.parent().hasClass("filterQa")) {
        $target.click(function (e) {
            $("#filterQ").val("");
        })
    }

    $target.blur(function () {
    });
}

// new row 
function addRow(row) {
    var current = 5;
    var newRow = { title: "new Title", duration: "1 day" };
    var rowData = grid.getData();
    var nRow = nItem(data.length + 1, row, rowData.getItem(row).indent + 1);
    rowData.insertItem(row + 1, nRow);
    //data.push(nRow);
    grid.setData(rowData);
    grid.render();
    grid.scrollRowIntoView(current, false);
}

/*nRow*/
function nItem(i, parent, indent) {
    var d = {};
    d["id"] = "id_" + i;
    d["indent"] = indent;
    d["parent"] = parent;
    d["operator"] = "增加 " + i;
    d["part"] = "EYA001" + i % 7 + "_" + i;
    d["draw"] = "EYA001" + i % 7;
    d["description"] = "keep your mind!";
    d["qty"] = i % 7;
    d["createTime"] = '2021-02-24';
    d["mFrom"] = "M";
    d["state"] = i % 2 == 0;
    return d;
}

$(function () {
    var indent = 0;
    var parents = [];


    $("#excel").bind("click", function () {
        grid.excel({ exportExt: true });
    });

    $("#scrollRowIntoView").bind("click", function (e) {
        e.stopPropagation();
        e.preventDefault();
    })

    $("#level").bind("click", function (e) {
        e.stopPropagation();
        e.preventDefault();
    })

    $("#levelOp").change(function (e) {
        var optionVal = $("#levelOp option:selected").val();
        if (optionVal == "ALL") {
            levelIx = 0;
        } else {
            levelIx = optionVal;
        }

        updateFilter();
    });

    // add new row command
    $("#addRow").bind("click", function (e) {
        var rows = grid.getSelectedRows();
        addRow(rows[0]);
    })

    $("#removeRow").bind("click", function (e) {
        var rows = grid.getSelectedRows();
        dataView.deleteItem(grid.getDataItem(rows[0]).id);
        grid.invalidate();
    })

    var lastQ = "";
    var lastIx = -1;
    $("#scrollRowIntoViewQuery").bind("click", function (e) {

        var query = $("#scrollRowIntoViewSearch").val();
        if (lastQ != query) {
            lastIx = -1;
            lastQ = query;
        }

        //  
        lastIx = dataView.getIndexByQuery(function (s) {
            return s["part"].indexOf(query) > -1;
        }, lastIx);
        grid.scrollRowIntoView(lastIx);
        grid.flashCell(lastIx, grid.getColumnIndex("part"), 100);
    })

    // prepare the data
    for (var i = 0; i < 10000; i++) {
        var d = (data[i] = {});
        var parent;

        if (Math.random() > 0.8 && i > 0) {
            indent++;
            parents.push(i - 1);
        } else if (Math.random() < 0.3 && indent > 0) {
            indent--;
            parents.pop();
        }

        if (parents.length > 0) {
            parent = parents[parents.length - 1];
        } else {
            parent = null;
        }

        d["id"] = "id_" + i;
        d["indent"] = indent;
        d["parent"] = parent;
        d["operator"] = "Task " + i;
        d["part"] = "EYA001" + i % 7 + "_" + i;
        d["draw"] = "EYA001" + i % 7;
        d["description"] = "Keep on going never give up !";
        d["qty"] = i % 7;
        d["createTime"] = '2021-02-24';
        d["mFrom"] = pickRandomFromroperty(mFroms);
        d["state"] = i % 2 == 0;
    }

    // initialize the model
    dataView = new Slick.Data.DataView({ inlineFilters: true });
    dataView.beginUpdate();
    dataView.setItems(data);
    dataView.setFilter(myFilter);
    dataView.endUpdate();

    headerMenuAttatchment(columns);
    // initialize the grid
    grid = new Slick.Grid("#myGrid", dataView, columns, options);
    grid.setSourceData(data);

    // 编辑
    //可编辑事件失焦前触发的函数
    grid.onBeforeEditCell.subscribe(function (e, args) {
        item = dataView.getItem(args.row);
        if (item.state) {
            return false;
        }
    });
    //可编辑事件失焦后触发的函数
    grid.onBeforeCellEditorDestroy.subscribe(function (e, args) {
        console.log(item);//这里的args与onBeforeEditCell 中的不同，失去焦点之后会把当前行的对象丢失
        item = {};
    });

    grid.onCellChange.subscribe(function (e, args) {
        dataView.updateItem(args.item.id, args.item);
    });

    // pager 
    var pager = new Slick.Controls.Pager(dataView, grid, $("#pager"));

    var checkboxSelector = new Slick.CheckboxSelectColumn({
        cssClass: "slick-cell-checkboxsel"
    });
    grid.setSelectionModel(new Slick.RowSelectionModel({ selectActiveRow: false }));
    grid.registerPlugin(checkboxSelector);
    var columnpicker = new Slick.Controls.ColumnPicker(columns, grid, options);

    grid.setSelectionModel(new Slick.CellSelectionModel());
    //grid.setSelectionModel(new Slick.RowSelectionModel());

    grid.registerPlugin(new Slick.AutoTooltips());

    // move the filter panel defined in a hidden div into grid top panel
    $("#inlineFilterPanel")
        .appendTo(grid.getTopPanel())
        .show();

    // wire up the search textbox to apply the filter to the model
    $("#txtSearch,#txtSearch2").keyup(function (e) {
        Slick.GlobalEditorLock.cancelCurrentEdit();

        // clear on Esc
        if (e.which == 27) {
            this.value = "";
        }

        searchString = this.value;
        updateFilter();
    });

    var h_runfilters = null;

    // wire up the slider to apply the filter to the model
    $("#pcSlider,#pcSlider2").slider({
        "range": "min",
        "slide": function (event, ui) {
            Slick.GlobalEditorLock.cancelCurrentEdit();

            if (percentComFromleteThreshold != ui.value) {
                window.clearTimeout(h_runfilters);
                h_runfilters = window.setTimeout(updateFilter, 10);
                percentComFromleteThreshold = ui.value;
            }
        }
    });

    function updateFilter() {
        dataView.setFilterArgs({
            searchString: searchString
        });
        dataView.refresh();
    }

    var temFrom = columns[1];
    var gp = columns[1].group;
    columns[1] = checkboxSelector.getColumnDefinition();
    columns[1].group = gp;
    columns[1].expend = true;


    // set keyboard focus on the grid
    grid.getCanvasNode().focus();
    // https://www.cnblogs.com/fszz/articles/5655154.html
    var copyExtManager = new Slick.CellExternalFullCopyManager();
    //grid.registerPlugin(copyManager);
    grid.registerPlugin(copyExtManager);


    copyExtManager.onPasteCells.subscribe(function (e, args) {
        if ($(e.target).hasClass("bom-past")) {
            dataViewOnPastNode(args);
            return true;
        }

        return false;
    });


    // 自定表头按钮
    var headerMenuPlugin = new Slick.Plugins.HeaderMenu({});

    headerMenuPlugin.onBeforeMenuShow.subscribe(function (e, args) {
        var menu = args.menu;

    });

    headerMenuPlugin.onCommand.subscribe(function (e, args) {
        if (args.command == "filter") {
            searchString = args.item.filterValue;
            Slick.GlobalEditorLock.cancelCurrentEdit();
            dataView.refresh();
        }
    });

    grid.registerPlugin(headerMenuPlugin);

    // checkbox
    var checkboxSelector = new Slick.CheckboxSelectColumn({
        cssClass: "slick-cell-checkboxsel"
    });

    grid.onAddNewRow.subscribe(function (e, args) {
        var item = {
            "id": "new_" + (Math.round(Math.random() * 10000)),
            "indent": 0,
            "title": "New task",
            "duration": "1 day",
            "percentComFromlete": 0,
            "start": "01/01/2009",
            "finish": "01/01/2009",
            "effortDriven": false
        };
        $.extend(item, args.item);
        dataView.addItem(item);
    });


    // key ctrl+a / ctrl+z
    grid.onKeyDown.subscribe(function (e) {

        // select all rows on ctrl-a
        if (!(e.which == 65 || e.which == 90 || e.which == 70) || !e.ctrlKey) {
            return false;
        }

        if (e.which == 65) {
            var rows = [];
            for (var i = 0; i < dataView.getLength(); i++) {
                rows.push(i);
            }
            grid.setSelectedRows(rows);
            e.preventDefault();
        }

        if (e.which == 90) {
            var rows = [];
            grid.setSelectedRows(rows);
            e.preventDefault();
        }

        if (e.which == 70) {
            e.preventDefault();
        }

    });


    // tree toggle
    grid.onClick.subscribe(function (e, args) {
        if ($(e.target).hasClass("toggle")) {
            var item = dataView.getItem(args.row);
            if (item) {
                if (!item._collapsed) {
                    item._collapsed = true;
                } else {
                    item._collapsed = false;
                }

                dataView.updateItem(item.id, item);
            }
            e.stopImmediatePropagation();
        }

        if ($(e.target).hasClass("cell-a-btn")) {
            if ($(e.target).hasClass("cell-a-add")) {
                addRow(args.row);
            }

            if ($(e.target).hasClass("cell-a-delete")) {

            }
        }
    });



    // contextMenu
    grid.onContextMenu.subscribe(function (e) {
        e.preventDefault();
        var cell = grid.getCellFromEvent(e);
        $("#contextMenu")
            .data("row", cell.row)
            .css("top", e.pageY)
            .css("left", e.pageX)
            .show();
        $("body").one("click", function () {
            $("#contextMenu").hide();
        });
    });

    // wire up model events to drive the grid
    dataView.onRowCountChanged.subscribe(function (e, args) {
        grid.updateRowCount();
        grid.render();
    });

    dataView.onRowsChanged.subscribe(function (e, args) {
        grid.invalidateRows(args.rows);
        grid.render();
    });

    var h_runfilters = null;

    // wire up the slider to apply the filter to the model
    $("#pcSlider").slider({
        "range": "min",
        "slide": function (event, ui) {
            Slick.GlobalEditorLock.cancelCurrentEdit();

            if (percentComFromleteThreshold != ui.value) {
                window.clearTimeout(h_runfilters);
                h_runfilters = window.setTimeout(dataView.refresh, 10);
                percentComFromleteThreshold = ui.value;
            }
        }
    });
    grid.setOptions({ autoEdit: true });
    // wire up the search textbox to apply the filter to the model
    $("#txtSearch").keyup(function (e) {
        Slick.GlobalEditorLock.cancelCurrentEdit();

        // clear on Esc
        if (e.which == 27) {
            this.value = "";
        }

        searchString = this.value;
        dataView.refresh();
    })
})